home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / Multi / AppDelegate.m < prev    next >
Text File  |  1995-06-12  |  13KB  |  413 lines

  1. /*----------------------------------------------------------------------------     
  2.      This file is set up for a width of 130 columns, with tab stops
  3.      every two spaces.
  4.      
  5.      HISTORY 
  6.      
  7.          10Oct93    DM    New
  8. ----------------------------------------------------------------------------*/
  9.  
  10. #import <mach/cthreads.h>
  11.  
  12. #import "AppDelegate.h"
  13. #import "CircleView.h"
  14.  
  15. static any_t increasingFunction(self)
  16. AppDelegate    *self;
  17. {
  18.     /*---------------------------------------------------------------
  19.        Simple function that just generates an increasing series
  20.          of numbers to display.  this runs as an independent
  21.          thread; we're forked and detached, then grab a connection to 
  22.          the main thread,and start sending messages to it.
  23.          
  24.          All four of these functions share some code.  It should
  25.          probably be factored out into a single method so the line
  26.          count can be reduced.
  27.     ---------------------------------------------------------------*/
  28.     id        proxy;                                            // "proxy" object to the main server; essentially "self"
  29.     int        i;                                                    // generic int
  30.         
  31.         // Get a connection to the main server.  This allows us to be detached,
  32.         // yet talk to appkit and the DPS in a thread-safe way.
  33.         
  34.     proxy = [NXConnection connectToName:"fooServer"];
  35.     
  36.         // If we got nothing on the connect attempt, or if the object we got back
  37.         // does not speak our "language", then punt.
  38.         
  39.     if((proxy == nil) || (![proxy conformsTo:@protocol(ServerInterface)]))
  40.         {
  41.             printf("Couldn't get connection to server object, or protocol is hosed\n");
  42.             cthread_exit(0);
  43.         }
  44.     
  45.         // Loop forever, generating an increasing sequence.  We wrap after
  46.         // some arbitrarily large number so we don't get overflow.
  47.         
  48.     while(YES)
  49.         {    
  50.           i = 0;
  51.             while(i < 128000)
  52.                 {
  53.                     [proxy showIncreasing:i];                            // Tell the main thread to display this number
  54.                     i++;
  55.                     
  56.                     if(!self->isRunning)
  57.                         cthread_exit(0);
  58.                     cthread_yield();                                            // Be polite to the scheduler (not required)
  59.                 }
  60.         }
  61.         
  62.     return 0;
  63. }
  64.  
  65. static any_t fibFunction(self)
  66. AppDelegate    *self;
  67. {
  68.  /*------------------------------------------------------------------------
  69.     Much like the above.  We're running as a thread, and attach to the
  70.         DO server and message that.  We just generate a series of fib 
  71.         numbers for display.
  72.  ------------------------------------------------------------------------*/
  73.     id        proxy;                                                            // Proxy to main server object
  74.     int        i, j, sum;
  75.     
  76.         // Get connection to main server
  77.             
  78.     proxy = [NXConnection connectToName:"fooServer"];
  79.     
  80.             // If we got nothing on the connect attempt, or if the object we got back
  81.             // does not speak our "language", then punt.
  82.         
  83.     if((proxy == nil) || (![proxy conformsTo:@protocol(ServerInterface)]))
  84.         {
  85.             printf("Couldn't get connection to server object\n");
  86.             cthread_exit(0);
  87.         }
  88.     
  89.         // Generate new fib numbers forever.  Roll over after some arbitrarily
  90.         // large number to prevent overflow.
  91.         
  92.     while(YES)
  93.         {    
  94.           i = 0; j = 1; sum = 0;
  95.             [proxy showFib:i];
  96.             
  97.             while(i < 128000)
  98.                 {
  99.                     sum = i + j;
  100.                     [proxy showFib:sum];
  101.                     i = j;
  102.                     j = sum;
  103.                     
  104.                     if(!self->isRunning)
  105.                         cthread_exit(0);
  106.                     
  107.                     cthread_yield();                                        // Be polite to the scheduler (not required)
  108.  
  109.                 }
  110.         }
  111.         
  112.     return 0;
  113. }
  114.  
  115. static any_t primeFunction(self)
  116. AppDelegate    *self;
  117. {
  118.  /*------------------------------------------------------------------------
  119.     Much like the above.  We're running as a thread, and attach to the
  120.         DO server and message that.  We just generate a series of prime 
  121.         numbers for display.  I have no idea how the algo here works; just
  122.         cut & pasted from something else.
  123.  ------------------------------------------------------------------------*/
  124.     id        proxy;                                                            // Proxy to main server object
  125.     int     counter, possiblePrime = 5, testLimit;
  126.     BOOL isPrime;
  127.     List *primeList;
  128.     
  129.         // Get connection to main server
  130.             
  131.     proxy = [NXConnection connectToName:"fooServer"];
  132.     
  133.         // If we got nothing on the connect attempt, or if the object we got back
  134.         // does not speak our "language", then punt.
  135.         
  136.     if((proxy == nil) || (![proxy conformsTo:@protocol(ServerInterface)]))
  137.         {
  138.             printf("Couldn't get connection to server object\n");
  139.             cthread_exit(0);
  140.         }
  141.     
  142.         // Sleaze alert: Lists are intended to hold ids, pointers to objects.  If
  143.         // we squint, and don't care a lot about nicities, we can also store ints
  144.         // in them.  The access is pretty slow, since it takes a function call
  145.         // to find the contents of an address.  But we could fix that if we liked
  146.         // by just doing some pointer arithmetic into the List.
  147.         
  148.     primeList = [[List alloc] init];
  149.     [primeList addObject:(id)2];
  150.     [primeList addObject:(id)3];
  151.     
  152.      while (YES)                                                         // Repeat forever
  153.     {
  154.             isPrime = YES;
  155.             testLimit = sqrt(possiblePrime);
  156.              for (counter=1; isPrime && ((int)[primeList objectAt:counter]<=testLimit); counter++)
  157.             if (possiblePrime % (int)[primeList objectAt:counter] == 0)
  158.                 isPrime = NO;
  159.                                 
  160.         if (isPrime)
  161.                     {
  162.                         [primeList addObject:(id)possiblePrime];
  163.                         [proxy showPrime:possiblePrime];
  164.                     }
  165.          possiblePrime += 2;
  166.          
  167.          if(!self->isRunning)
  168.                         cthread_exit(0);
  169.         
  170.         cthread_yield();                                            // Be polite to the scheduler (not required)
  171.  
  172.          if(possiblePrime > 128000)                        // Begin again to prevent overflow
  173.              {
  174.                  possiblePrime = 5;
  175.                 [primeList free];
  176.                 primeList = [[List alloc] init];
  177.                 [primeList addObject:(id)2];
  178.                 [primeList addObject:(id)3];
  179.             }
  180.     }
  181.  
  182.  return 0;
  183. };                                                                                // end of primeFunction
  184.  
  185. static any_t circleFunction(self)
  186. AppDelegate    *self;
  187. {
  188.  /*------------------------------------------------------------------------
  189.     Much like the above.  We're running as a thread, and attach to the
  190.         DO server and message that.  We generate a series of points and
  191.         radii, and send those to the main thread server.  that draws
  192.         the circles. 
  193.  ------------------------------------------------------------------------*/
  194.     id            proxy;                                                            // Proxy to main server object
  195.     int            maxHeight = 156, maxWidth = 255;        // aprox. dimensions of the View
  196.     NXPoint    center;
  197.     float        radius;
  198.     int            x,y,r;                                                            // int versions of x, y, radius
  199.  
  200.         // Get connection to main server.  Yeah, this common code ought to
  201.         // be factored out into its own method.  Sue me.
  202.             
  203.     proxy = [NXConnection connectToName:"fooServer"];
  204.     
  205.         // If we got nothing on the connect attempt, or if the object we got back
  206.         // does not speak our "language", then punt.
  207.         
  208.     if((proxy == nil) || (![proxy conformsTo:@protocol(ServerInterface)]))
  209.         {
  210.             printf("Couldn't get connection to server object\n");
  211.             cthread_exit(0);
  212.         }
  213.     
  214.         // Generate a series of points and radii, and pass them off 
  215.         // to the main thread for drawing. 
  216.             
  217.     srandom(1);                                                        // initialize rng
  218.     
  219.     while(YES)                                                        // loop forever
  220.         {
  221.             x = random(); y = random(); r = random();
  222.                         
  223.                 // Get them scaled back to about the size of the view.
  224.         
  225.             center.x = (float)(((double)x/(double)MAXINT) * (double)maxWidth);
  226.             center.y = (float)(((double)y/(double)MAXINT) * (double)maxHeight);
  227.             radius   = (float)((((double)r/(double)MAXINT)*2.0) * (double)maxHeight);
  228.         
  229.             [proxy drawRandomCircleAt:center withRadius:radius];
  230.             
  231.             if(!self->isRunning)
  232.                         cthread_exit(0);
  233.             
  234.             cthread_yield();                                // Be polite to the scheduler.
  235.  
  236.         }
  237.     
  238.     return 0;
  239. }    
  240.     
  241.  
  242. @implementation AppDelegate
  243.  
  244.     // The main methods called by the threads, which output things to the screen.  
  245.     // These are the implementations of the protocol declaration.
  246.     
  247. - showIncreasing                                                // Show an increasing number in the window
  248.     :(int)pNumber;                                                // INPUT: the number to show
  249.     /*-------------------------------------------------------------------------
  250.        Make an addition to the scrolling display of data in the ScrollView
  251.          for the "increasing number" display.
  252.     -------------------------------------------------------------------------*/
  253.     Text        *textObj;
  254.     char        theNumber[256];
  255.     
  256.     sprintf(theNumber, "%d\n", pNumber);
  257.     textObj = [increasingDisp docView];
  258.     
  259.     [self addToText:textObj string:theNumber];
  260.     
  261.     return self;                                                        
  262. }                                                                                // end of showIncreasing
  263.     
  264. - showPrime                                                            // Show a prime number in the window
  265.     :(int)pPrime;                                                    // INPUT: the prime to show
  266. /*-------------------------------------------------------------------------
  267.        Make an addition to the scrolling display of data in the ScrollView
  268.          for the "increasing prime" display.
  269.     -------------------------------------------------------------------------*/
  270.  
  271.     Text        *textObj;
  272.     char        theNumber[256];
  273.     
  274.     sprintf(theNumber, "%d\n", pPrime);
  275.     textObj = [primeDisp docView];
  276.     
  277.     [self addToText:textObj string:theNumber];
  278.  
  279.     return self;                                                        
  280. }                                                                                // end of showPrime:
  281.     
  282. - showFib                                                                // Show a fibonaci number in the window
  283.     :(int)pFib;                                                        // INPUT: the fib to show
  284.     /*-------------------------------------------------------------------------
  285.        Make an addition to the scrolling display of data in the ScrollView
  286.          for the "increasing fibonacci" display.
  287.     -------------------------------------------------------------------------*/
  288.  
  289.     Text        *textObj;
  290.     char        theNumber[256];
  291.     
  292.     sprintf(theNumber, "%d\n", pFib);
  293.     textObj = [fibDisp docView];
  294.     
  295.     [self addToText:textObj string:theNumber];
  296.         
  297.     return self;                                                        
  298. }                                                                                // end of showFib:
  299.     
  300. - drawRandomCircleAt                                        // Draw a circle at the given point with the given radius
  301.     :(NXPoint)pPoint                                            // INPUT: where to draw it at (the center)
  302.     withRadius:(float)pRadius;                        // INPUT: the radius
  303.     /*-------------------------------------------------------------------------------
  304.        Add a circle to the view that displays the random circles.  This also adds
  305.          a circle to the display list kept in the CircleView, which is probably
  306.          overkill.  But we will be able to redraw it in its current state anywhere.
  307.     -------------------------------------------------------------------------------*/
  308.     [circleView addCircleAt:pPoint withRadius:pRadius];
  309.     [circleView display];
  310.     
  311.     return self;
  312. }
  313.  
  314. // App initialization delegate method
  315.  
  316. - appDidInit:sender;
  317. {    
  318.       // Vend ourselves to the universe (and our threads, too.)
  319.         // This is run from the appkit; the idea is to allow anyone
  320.         // to call us, and we handle all talking to the appkit.
  321.     
  322.     [NXConnection setDefaultTimeout:200000];                // Timeout period, in milliseconds
  323.         
  324.     connection = [NXConnection registerRoot:self withName:"fooServer"];
  325.     [connection runFromAppKit];
  326.             
  327.     return self;
  328. }
  329.  
  330. - doThreads:sender;                                            // Starts doing things--slamming numbers to the screen
  331. {
  332.   /*---------------------------------------------------------------
  333.        Do some stuff. Namely, start the threads that display
  334.          things to the screen. We have functions that do nothing 
  335.          but generate output; they message us via distributed objects
  336.          and tell us what to display, and we do it.
  337.     ---------------------------------------------------------------*/
  338.     
  339.         // Clear out any existing cruft in the views.
  340.     
  341.     [circleView emptyCircles];
  342.     [circleView display];
  343.     
  344.     [[increasingDisp docView] selectAll:self];
  345.     [[increasingDisp docView] delete:self];
  346.     
  347.     [[fibDisp docView] selectAll:self];
  348.     [[fibDisp docView] delete:self];
  349.  
  350.     [[primeDisp docView] selectAll:self];
  351.     [[primeDisp docView] delete:self];
  352.  
  353.     
  354.         // Break off all the threads for the stuff we want to do-- draw circles,
  355.         // calculate primes, whatever.
  356.  
  357.         // "I woke up this morning with a bad hangover, and my cthread was
  358.         //  missing.  This happens all the time.  It's detachable."
  359.         //       -- Not King Missile
  360.  
  361.     isRunning = YES;
  362.     
  363.     cthread_detach(cthread_fork(increasingFunction, self));
  364.     cthread_detach(cthread_fork(fibFunction, self));
  365.     cthread_detach(cthread_fork(primeFunction, self));
  366.     cthread_detach(cthread_fork(circleFunction, self));
  367.         
  368.     return self;
  369. }
  370.  
  371. - stopThreads:sender;                                        // Stops all the treads
  372. {
  373.   /*-----------------------------------------------------------------------
  374.        Stops all the threads, while leaving the display as is.
  375.     -----------------------------------------------------------------------*/
  376.     
  377.     isRunning = NO;
  378.     
  379.     return self;
  380. }    
  381.     
  382.     
  383. - addToText                                                            // Utility method--adds text at end of given text obj
  384.     :(Text*)pTextObj                                            // INPUT: text obj to add to
  385.     string:(char*)pString;                                // INPUT: the text we're adding
  386. {
  387.   /*------------------------------------------------------------------------------
  388.        This would be better implemented as a category method to the Text object,
  389.          but that would probably just confuse things for the rookies out there.
  390.          We have very similar code in three of our functions, that just add
  391.          a number to the end of a scrolling text display.  This does that, given
  392.          the text object passed in and the text to append.
  393.          
  394.          If we _did_ use a category method, everyone could use this method, which
  395.          is pretty useful.
  396.     ------------------------------------------------------------------------------*/
  397.     int        length;                                                    // How many chars are in the text object
  398.         
  399.     length = [pTextObj textLength];                // find out how long...
  400.     [pTextObj setSel:length :length];            // get a null selection at the end...
  401.     [pTextObj replaceSel:pString];                // and replace it with our new text
  402.     
  403.     [pTextObj scrollSelToVisible];                // make sure we can see it.
  404.     
  405.     return self;
  406. }
  407.  
  408. @end
  409.